'Andrew's Functions
' $HeadURL: http://gabbscript.googlecode.com/svn/trunk/Gabbscript/AndrewFunctions.vb $
' $Author: andrewshen123 $
' $Revision: 90 $
' $Date: 2007-11-08 19:15:35 +0000 (Thu, 08 Nov 2007) $

Imports System.IO

Module AndrewFunctions

    ' An table containing all open files used by FILE I/O FUNCTIONS
    Dim openFiles As Hashtable = New Hashtable()

    ' Register the functions
    Sub RegisterFunctions(ByRef funcList As FunctionList)
        funcList.RegisterFunction("IF", AddressOf IF_)
        funcList.RegisterFunction("FOR", AddressOf FOR_)
        funcList.RegisterFunction("LOOP", AddressOf LOOP_)
        funcList.RegisterFunction("FOPEN", AddressOf FOPEN)
        funcList.RegisterFunction("FCLOSE", AddressOf FCLOSE)
        funcList.RegisterFunction("FWRITE", AddressOf FWRITE)
        funcList.RegisterFunction("FPEEK", AddressOf FPEEK)
        funcList.RegisterFunction("FREAD", AddressOf FREAD)
        funcList.RegisterFunction("FREADL", AddressOf FREADL)
        funcList.RegisterFunction("FFLUSH", AddressOf FFLUSH)
        funcList.RegisterFunction("SET", AddressOf SETVAR)
        funcList.RegisterFunction("DEL", AddressOf DEL)
        funcList.RegisterFunction("MOV", AddressOf MOV)
        funcList.RegisterFunction("CPY", AddressOf CPY)
        funcList.RegisterFunction("RNM", AddressOf RNM)
    End Sub

    ' PROGRAM FLOW

    ' IF: Conditional branch
    Function IF_(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 5 Then Return False

        ' Declarations
        Dim val1 As Argument = args.Item(0)             ' The first value to compare
        Dim op As String = args.Item(1).Data            ' The operator to compare the values with (i.e. ">", "=" or "<"
        Dim val2 As Argument = args.Item(2)             ' The second value to compare
        Dim ifTrue As Integer = args.Item(3).Data       ' Where to jump if the comparison returns true
        Dim ifFalse As Integer = args.Item(4).Data      ' Where to jump if the comparison returns false

        ' Calls the comparison function to compare the two values
        If script.Compare(val1, op, val2) Then
            ' If true, jumps to ifTrue
            script.SetInstructionPointer(ifTrue)
        Else
            ' If false, jumps to isFalse
            script.SetInstructionPointer(ifFalse)
        End If

        ' Function succeeded! Yay!
        Return True

    End Function
    ' FOR: For loop
    Function FOR_(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 5 Then Return False

        ' Declarations
        Dim var As Argument = args.Item(0)                  ' The counter
        Dim lim As Double = args.Item(1).Data               ' The value the counter is supposed to reach
        Dim inc As Double = args.Item(2).Data               ' The increment to raise the counter by
        Dim blockStart As Integer = args.Item(3).Data       ' Where the looped code starts
        Dim blockEnd As Integer = args.Item(4).Data + 1     ' Where the looped code ends. Add 1 because the instruction pointer is 0 based (starts at 0 instead of 1)

        ' Checks for infinite loop
        If inc > 0 And lim < var.Data Or inc < 0 And lim > var.Data Or inc = 0 Then Return False

        If var.Data <> lim Then
            ' If the current value of var does not equal lim, jumps to blockStart
            script.SetInstructionPointer(blockStart)
            ' Then increments the counter
            var.Data += inc
        Else
            ' If it does equal, jump to the line after the looped block
            script.SetInstructionPointer(blockEnd)
        End If

        ' Function succeeded! Yay!
        Return True

    End Function
    ' LOOP: While/until loops
    Function LOOP_(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 5 Then Return False

        ' Declarations
        Dim loopFrom As Integer = args.Item(0).Data     ' Where to loop from
        Dim val1 As Argument = args.Item(1)             ' The first value to compare
        Dim op As String = args.Item(2).Data            ' The operator to compare with
        Dim val2 As Argument = args.Item(3)             ' The second value to compare
        Dim cond As Char = args.Item(4).Data            ' Either "w" for While, or "u" for Until

        Select Case cond
            Case "w"
                ' If it's a While loop, check if the comparison returns true
                If script.Compare(val1, op, val2) Then
                    ' If so, jump to loopFrom
                    script.SetInstructionPointer(loopFrom)
                End If
            Case "u"
                ' If it's an Until loop, check if the comparison returns false
                If Not script.Compare(val1, op, val2) Then
                    ' If so, jump to loopFrom
                    script.SetInstructionPointer(loopFrom)
                End If
            Case Else
                ' If the condition is anything else, complain
                Return False
        End Select

        ' Function succeeded! Yay!
        Return True

    End Function

    ' FILE I/O FUNCTIONS

    ' FOPEN: Opens file to read/write to
    Function FOPEN(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declarations
        Dim filename As String = args.Item(0).Data  ' The name of the file to open
        Dim type As Char = args.Item(1).Data        ' Either "w" for Write, or "r" for Read

        Select Case type
            Case "w"
                ' If Write, open the file for writing
                Dim file As StreamWriter = New StreamWriter(filename)
                ' Then add it to the table of open files
                openFiles.Add(filename, file)
            Case "r"
                ' If Read, open the file for reading
                Dim file As StreamReader = New StreamReader(filename)
                ' Then add it to the table of open files
                openFiles.Add(filename, file)
            Case Else
                ' If the type is anything else, complain
                Return False
        End Select

        ' Function succeeded! Yay!
        Return True

    End Function
    ' FCLOSE: Closes the stream (and flushes the buffer if necessary)
    Function FCLOSE(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 1 Then Return False

        ' Declaration
        Dim file As String = args.Item(0).Data  ' The file to close

        ' Checks if the file exists in the table
        If openFiles.Contains(file) Then
            ' Closes the file
            openFiles.Item(file).close()
            ' Then removes it from the list
            openFiles.Remove(file)
        Else
            ' If not, complain
            Return False
        End If

        ' Function succeeded!(Yay!)
        Return True

    End Function
    ' FWRITE: Writes to a stream
    Function FWRITE(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct range of arguments
        If args.Count < 2 Then Return False

        ' Declarations
        Dim file As String = args.Item(0).Data  ' The file to write to
        Dim i As Integer                        ' A counter for the loop

        ' Checks if the file exists in the table, and is a StreamWriter, because if it were a StreamReader, the computer would get angry
        If openFiles.Contains(file) And openFiles.Item(file).GetType.ToString() = "System.IO+StreamWriter" Then
            For i = 1 To args.Count() - 1
                ' Writes the value of each argument to a seperate line in the stream
                openFiles.Item(file).WriteLine(args.Item(i).Data)
            Next
            ' Function succeeded! Yay!
            Return True
        End If

        ' Otherwise, complain
        Return False

    End Function
    ' FPEEK: Gets the next character in a stream, but does not consume it
    Function FPEEK(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declaration
        Dim file As String = args.Item(0).Data  ' The file to read from

        ' Checks if the file exists in the table, and is a StreamReader, because if it were a StreamWriter, the computer would get angry
        If openFiles.Contains(file) Then
            ' If so, set the value of the variable in the second argument to the next character in the file, but does not advance the pointer of the stream
            args.Item(1).Data = openFiles.Item(file).Peek
            ' Function succeeded! Yay!
            Return True
        End If

        ' Otherwise, complain
        Return False

    End Function
    ' FREAD: Gets the next character in a stream
    Function FREAD(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declaration
        Dim file As String = args.Item(0).Data  ' The file to read from

        ' Checks if the file exists in the table, and is a StreamReader, because if it were a StreamWriter, the computer would get angry
        If openFiles.Contains(file) Then
            ' If so, set the value of the variable in the second argument to the next character in the file
            args.Item(1).Data = openFiles.Item(file).Read
            ' Function succeeded! Yay!
            Return True
        End If

        ' Otherwise, complain
        Return False

    End Function
    ' FREADL: Gets the next line in a stream
    Function FREADL(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declaration
        Dim file As String = args.Item(0).Data  ' The file to read from

        ' Checks if the file exists in the table, and is a StreamReader, because if it were a StreamWriter, the computer would get angry
        If openFiles.Contains(file) Then
            ' If so, set the value of the variable in the second argument to the next line in the file
            args.Item(1).Data = openFiles.Item(file).ReadLine
            ' Function succeeded! Yay!
            Return True
        End If

        ' Otherwise, complain
        Return False

    End Function
    ' FFLUSH: Flushes a stream
    Function FFLUSH(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 1 Then Return False

        ' Declarations
        Dim stream As String = args.Item(0).Data  ' The stream to flush. Heh. Flush. Like a toilet.

        ' Checks if the stream exists in the table, and is a StreamWriter, because if it were a StreamReader, the computer would get angry
        If openFiles.Contains(stream) And openFiles.Item(stream).GetType.ToString() = "System.IO+StreamWriter" Then
            ' If true, flush the stream
            openFiles.Item(stream).flush()
            ' Function succeeded! Yay!
            Return True
        End If

        ' Otherwise, complain
        Return False

    End Function
    ' SETVAR: Sets a variable
    Function SETVAR(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Set the value of the first argument to that of the second
        args.Item(0).Data = args.Item(1).Data

        ' Function succeeded! Yay!
        Return True

    End Function

    ' FILESYSTEM FUNCTIONS

    ' DEL: Deletes a file
    Function DEL(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declarations
        Dim filename As String = args.Item(0).Data  ' The file to delete
        Dim type As Char = args.Item(1).Data        ' How to delete (permanently, or just move to the recycle bin)

        Select Case type
            Case "k"
                ' KILL THE FILE. MWAHAHAHAHAHAHAHAHAHAHAHA.
                My.Computer.FileSystem.DeleteFile(filename, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.DeletePermanently)
            Case "r"
                ' Just send the file to the recycle bin :(
                My.Computer.FileSystem.DeleteFile(filename, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.DeletePermanently)
            Case Else
                ' Complain
                Return False
        End Select

        ' Function succeeded! Yay!
        Return True

    End Function
    ' MOV: Moves a file
    Function MOV(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declarations
        Dim filename As String = args.Item(0).Data
        Dim moveTo As String = args.Item(1).Data

        ' Move the file
        My.Computer.FileSystem.MoveFile(filename, moveTo)

        ' Function succeeded! Yay!
        Return True

    End Function
    ' CPY: Copies a file
    Function CPY(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declarations
        Dim filename As String = args.Item(0).Data
        Dim copyTo As String = args.Item(1).Data

        ' Move the file
        My.Computer.FileSystem.CopyFile(filename, copyTo)

        ' Function succeeded! Yay!
        Return True

    End Function
    ' RNM: Renames a file
    Function RNM(ByVal args As ArgList, ByRef script As Script) As Boolean

        ' Checks for the correct number of arguments
        If args.Count <> 2 Then Return False

        ' Declarations
        Dim filename As String = args.Item(0).Data
        Dim renameTo As String = args.Item(1).Data

        ' Move the file
        My.Computer.FileSystem.RenameFile(filename, renameTo)

        ' Function succeeded! Yay!
        Return True

    End Function
End Module